package main

func (lex *Lexicon) NewNode() *Node {
	// Create new node with new label
	nNew, lNew := new(Node), new(Label)
	nUID, lUID := lex.newUID(), lex.newUID()
	nNew.UID, nNew.Label = nUID, lUID
	lNew.UID, lNew.Node = lUID, nUID
	// Add new node and label to lexicon
	nNew.Lexicon = lex
	lex.Nodes[nUID], lex.Labels[lUID] = nNew, lNew
	return nNew
}

func (n *Node) NewChild() *Node {
	child := n.Lexicon.NewNode()
	child.AddParents(n.UID)
	return child
}

func (n *Node) GetParents(extended bool) UIDs {
	if !extended {
		return n.Parents
	}

	all := makeUIDSet()
	lall := len(all)
	rents := makeUIDSet(n.Parents...)
	for {
		for puid := range rents {
			delete(rents, puid)
			if _, ok := all[puid]; ok {
				// Already included
				continue
			}
			// Add to all
			all.Add(puid)
			// Get (great-)*grandparents
			if p := n.Lexicon.Nodes[puid]; p != nil {
				rents.Add(p.Parents...)
			}
		}

		if len(all) > lall {
			lall = len(all)
		} else {
			break
		}
	}
	return all.UIDs()
}

func (n *Node) AddParents(parents ...UID) {
	newParents := makeUIDSet(n.Parents...)
	for _, puid := range parents {
		// Accept only Node UIDs
		if p, ok := n.Lexicon.Nodes[puid]; ok {
			p.Children = makeUIDSet(p.Children...).Add(n.UID).UIDs()
			newParents.Add(p.UID)
		}
	}
	n.Parents = newParents.UIDs()
	n.InheritFrom(parents...) // Inherit from immediate given parents
}

func (n *Node) RemoveParents(parents ...UID) {
	n.Parents = makeUIDSet(n.Parents...).Remove(parents...).UIDs()
	for _, puid := range parents {
		if p, ok := n.Lexicon.Nodes[puid]; ok {
			p.Children = makeUIDSet(p.Children...).Remove(n.UID).UIDs()
		}
	}
}

func (n *Node) InheritFrom(parents ...UID) {
	for _, puid := range parents {
		p, ok := n.Lexicon.Nodes[puid]
		if !ok {
			continue
		}
		// TODO Inherit inheritable fields
		for _, fuid := range p.Fields {
			f, ok := n.Lexicon.Fields[fuid]
			if !ok || !f.InhLabel {
				continue
			}
			// TODO
		}
		// TODO Inherit inheritable relations
		for _, ruid := range p.Relations {
			r, ok := n.Lexicon.Relations[ruid]
			if !ok || !r.InhLabel {
				continue
			}
			// TODO
		}
	}
}

func (n *Node) ReInherit(extended bool) {
	parents := n.GetParents(extended)
	n.InheritFrom(parents...)
}

/* ********************************** */

func (n *Node) GetFieldBySlug(slug string) *Field {
	// check each field, get label, compare slug
	for _, uid := n.Fields {
		fld := n.Lexicon.Fields[uid];
		lbl := n.Lexicon.Labels[fld.Label];
		if lbl.Slug == slug {
			return fld
		}
	}
	return nil
}

func (n *Node) NewField() *Field {
	// Create new field with new label
	fNew, lNew := new(Field), new(Label)
	fUID, lUID := n.Lexicon.newUID(), n.Lexicon.newUID()
	fNew.UID, fNew.Label, fNew.Node = fUID, lUID, n.UID
	lNew.UID, lNew.Node = lUID, n.UID
	// Add new field and label to lexicon
	n.Lexicon.Fields[fUID], n.Lexicon.Labels[lUID] = fNew, lNew
	// Add new field to node
	n.Fields = append(n.Fields, fUID)
	return fNew
}

/* ********************************** */

func (n *Node) NewRelation() *Relation {
	// Create new relation with new label
	rNew, lNew := new(Relation), new(Label)
	rUID, lUID := n.Lexicon.newUID(), n.Lexicon.newUID()
	rNew.UID, rNew.Label, rNew.Node = rUID, lUID, n.UID
	lNew.UID, lNew.Node = lUID, n.UID
	// Add new relation and label to lexicon
	n.Lexicon.Relations[rUID], n.Lexicon.Labels[lUID] = rNew, lNew
	// Add new relation to node
	n.Relations = append(n.Relations, rUID)
	return rNew
}

func (r *Relation) Add(uids ...UID) {
	r.Related = makeUIDSet(r.Related...).Add(uids...).UIDs()
}

func (r *Relation) Remove(uids ...UID) {
	r.Related = makeUIDSet(r.Related...).Remove(uids...).UIDs()
}
